﻿//-----------------------------------------------------------------------
// <copyright file="MotionBlurScrollViewer.xaml.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <summary>
// Implements a ScrollViewer that applies motion blur to its content upon scrolling.
// </summary>
namespace myTwitter
{
    using System;
    using System.Windows.Controls;
    using System.Windows.Media.Animation;
    using System.Windows.Media;
    using System.Windows;
    using myBoard.Framework.Effects;

    /// <summary>
    /// Subclassing ScrollViewer class and implementing a ScrollViewer with motion blur effect.
    /// </summary>
    public partial class MotionBlurScrollViewer : ScrollViewer
    {
        /// <summary>
        /// The name of the element in the scrollviewer template that encapsulates the content presenter.
        /// </summary>
        internal const string ScrollContentPresenterParentGridTemplateName = "PART_ScrollContentPresenterParentGrid";

        /// <summary>
        /// The maximum blurring magnitude.
        /// </summary>
        private const double MaxBlurAmount = 0.12 * 3;

        /// <summary>
        /// The maximum animation time (in milliseconds).
        /// </summary>
        private const int MaxAnimTime = 150 * 3;

        /// <summary>
        /// The motion blur effect object to be applied to ScrollViewer content when scrolling.
        /// </summary>
        private DirectionalBlur effect;

        /// <summary>
        /// The animation object that is used to animate the blur amount back to zero.
        /// </summary>
        private DoubleAnimation anim;

        /// <summary>
        /// Constructor - Initialize some internal fields.
        /// </summary>
        public MotionBlurScrollViewer()
        {
            InitializeComponent();
            //this.ScrollChanged += new ScrollChangedEventHandler(CustomScrollViewer_ScrollChanged);

            this.anim = new DoubleAnimation(0, TimeSpan.FromMilliseconds(MaxAnimTime));
            this.anim.AccelerationRatio = this.anim.DecelerationRatio = 0.5;

            //this.effect = new DirectionalBlur();
        }
        
        /// <summary>
        /// Apply the motion blur effect on PART_ScrollContentPresenterParentGrid, which will apply the effect
        /// to the content of the ScrollViewer.
        /// 
        /// For performance reasons, we do not apply the effect on PART_ScrollContentPresenter because the
        /// ContentPresenter’s dimensions can be many times that of the ScrollViewer itself.
        /// </summary>
        /*
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            Grid grid = (Grid)this.Template.FindName(ScrollContentPresenterParentGridTemplateName, this);
            if (grid != null)
            {
                grid.Effect = this.effect;
            }
        }*/

        /// <summary>
        /// When the ScrollChanged event is fired, we compute the direction of the motion blur
        /// (based on the amount of vertical/horizontal change). The magnitude of the blur effect
        /// is proportional to the ration of vertical/horizontal change over the height/width of the
        /// scroller extent.
        /// </summary>
        /// <param name="sender">The sender of the event, which is the ScrollViewer object.</param>
        /// <param name="e">The event arguments.</param>
        private void CustomScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            /*if (this.IsDeferredScrollingEnabled == false &&
                (e.VerticalChange != 0 || e.HorizontalChange != 0) &&
                this.effect != null)
            {
                // Compute the ratio of the scrolling amount to the extent size.
                double ratio = Math.Max(Math.Abs(e.HorizontalChange) / e.ExtentWidth, Math.Abs(e.VerticalChange) / e.ExtentHeight);

                if (ratio >= 0.005) // If ratio is more than 0.5% then we'll blur the content
                {
                    // We use an animation object to animate the blur amount back to zero.
                    // But in order to be able to set the value of blur amount, first we
                    // need to set the animation on the blur amount property to null.
                    this.effect.BeginAnimation(DirectionalBlur.BlurAmountProperty, null);

                    // Now we set the parameter values.
                    this.effect.Angle = Math.Atan2(e.VerticalChange, e.HorizontalChange);
                    this.effect.BlurAmount = ratio * MaxBlurAmount;

                    // The animation time is between 10 to 150 milliseconds, depending on 'ratio'.
                    // The animation time should be dependent on the value of 'ratio' in order to see the
                    // correct blurring behavior regardless of the scrolling method (i.e scrolling by
                    // dragging the thumb, by pressing PageUp or PageDown, or by pressing Ctrl+Home or Ctrl+End).
                    this.anim.Duration = TimeSpan.FromMilliseconds(Math.Sqrt(ratio) * MaxAnimTime);

                    // Finally, we will re-enable the animation on the blur amount to bring it back to zero.
                    // We animate the blur amount in order to get a more "realistic" behavior.
                    //
                    // Consider when the user scrolls the content of the ScrollViewer. The user will left-click
                    // on the scroll thumb and start dragging it. The user can stop scrolling by releasing the
                    // mouse button, or by keeping the mouse button pressed but stop moving the mouse. In the 
                    // latter case, no MouseUp event is fired, so if we were to "unblur" the content on MouseUP
                    // event, it wouldn't cover this case.
                    //
                    // But using an animation to bring the blur amount back to zero works in both scenarios.
                    // After computing and setting the blur amount we will immediately animate it back to zero
                    // in a short time interval. If the user keeps dragging the scroll thumb, the ScrollChanged
                    // event will be fired again, in which case we will re-compute and reset the blur amount. And
                    // if the user releases the mouse button or stops moving the mouse, the animation object will
                    // automatically "unblur" the content on the ScrollViewer in that short time interval.
                    this.effect.BeginAnimation(DirectionalBlur.BlurAmountProperty, this.anim);
                }
            }*/
        }
    }
}
